package com.hjw.dynamicdatasource.util;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hjw.dynamicdatasource.config.DynamicCacheManager;
import com.hjw.dynamicdatasource.mapper.DynamicMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 动态Mapper工厂，用于为动态生成的实体类创建Mapper实例
 * @author ivan
 */
@Slf4j
@Component
public class DynamicMapperFactory {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Autowired
    private DynamicCacheManager dynamicCacheManager;


    /**
     * 为指定实体类创建Mapper实例
     * @param entityClass 实体类
     * @return Mapper实例
     */
    @SuppressWarnings("unchecked")
    public <T> BaseMapper<T> createMapper(Class<T> entityClass) {
        // 检查缓存
        if (dynamicCacheManager.getMapperCache().containsKey(entityClass)){
            return (BaseMapper<T>) dynamicCacheManager.getMapperCache(entityClass);
        }
        
        try {
            // 获取表名
            String tableName = getTableName(entityClass);
            dynamicCacheManager.putTableNameCache(entityClass, tableName);
            
            // 创建代理Mapper实例
            BaseMapper<T> mapper = (BaseMapper<T>) Proxy.newProxyInstance(
                    BaseMapper.class.getClassLoader(),
                    new Class<?>[]{BaseMapper.class},
                    new DynamicMapperInvocationHandler<>(entityClass, sqlSessionFactory, tableName)
            );
            // 缓存Mapper实例
            dynamicCacheManager.putMapperCache(entityClass, mapper);
            
            return mapper;
        } catch (Exception e) {
            log.error("创建动态Mapper失败: {}", entityClass.getName(), e);
            throw new RuntimeException("创建动态Mapper失败", e);
        }
    }

    /**
     * 获取实体类对应的表名
     * @param entityClass 实体类
     * @return 表名
     */
    private String getTableName(Class<?> entityClass) {
        // 检查缓存
        if (dynamicCacheManager.getTableNameCache().containsKey(entityClass)){
            return dynamicCacheManager.getTableNameCache(entityClass);
        }
        
        // 从@TableName注解获取
        TableName tableNameAnnotation = entityClass.getAnnotation(TableName.class);
        if (tableNameAnnotation != null) {
            return tableNameAnnotation.value();
        }
        
        // 默认使用类名的下划线形式作为表名
        String className = entityClass.getSimpleName();
        StringBuilder tableName = new StringBuilder();
        for (int i = 0; i < className.length(); i++) {
            char c = className.charAt(i);
            if (i > 0 && Character.isUpperCase(c)) {
                tableName.append('_');
            }
            tableName.append(Character.toLowerCase(c));
        }
        return tableName.toString();
    }
    
    /**
     * 驼峰命名转下划线命名
     */
    private static String camelToUnderscore(String str) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i > 0 && Character.isUpperCase(c)) {
                result.append('_');
            }
            result.append(Character.toLowerCase(c));
        }
        return result.toString();
    }
    
    /**
     * 动态Mapper的InvocationHandler实现
     */
    private static class DynamicMapperInvocationHandler<T> implements InvocationHandler {
        
        private final Class<T> entityClass;
        private final SqlSessionFactory sqlSessionFactory;
        private final String tableName;
        
        public DynamicMapperInvocationHandler(Class<T> entityClass, SqlSessionFactory sqlSessionFactory, String tableName) {
            this.entityClass = entityClass;
            this.sqlSessionFactory = sqlSessionFactory;
            this.tableName = tableName;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();

            // 获取当前线程的SqlSession
            try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {
                // 使用动态SQL方式处理
                return handleWithDynamicSql(methodName, args, sqlSession);
            }
        }

        /**
         * 使用动态SQL处理
         */
        @SuppressWarnings("unchecked")
        private Object handleWithDynamicSql(String methodName, Object[] args, SqlSession sqlSession) throws NoSuchFieldException, IllegalAccessException {
            String sql = "";
            Map<String, Object> params = new HashMap<>();
            
            switch (methodName) {
                case "selectById":
                    sql = "SELECT * FROM " + tableName + " WHERE id = #{id}";
                    params.put("id", args[0]);
                    return executeDynamicQuery(sql, params, sqlSession, entityClass);
                case "selectList":
                    // 如果传入了QueryWrapper，需要特殊处理
                    if (args != null && args.length > 0 && args[0] instanceof QueryWrapper) {
                        return handleQueryWrapper((QueryWrapper<?>) args[0], sqlSession);
                    }
                    // 默认查询所有
                    sql = "SELECT * FROM " + tableName;
                    return executeDynamicQueryList(sql, params, sqlSession, entityClass);
                case "insert":
                    return handleInsert(args[0], sqlSession);
                case "updateById":
                    return handleUpdateById(args[0], sqlSession);
                case "deleteById":
                    sql = "DELETE FROM " + tableName + " WHERE id = #{id}";
                    params.put("id", args[0]);
                    return sqlSession.delete("com.hjw.dynamicdatasource.mapper.DynamicMapper.dynamicExecute", 
                            createDynamicExecuteParam(sql, params));
                case "selectMap":
                    sql = "SELECT * FROM " + tableName;
                    List<T> list = executeDynamicQueryList(sql, params, sqlSession, entityClass);
                    if (list == null || list.isEmpty()) {
                        return new HashMap<>();
                    }
                    String mapKey = args[1].toString();
                    Map<Object, T> resultMap = new HashMap<>();
                    for (T item : list) {
                        Field field = entityClass.getDeclaredField(mapKey);
                        field.setAccessible(true);
                        resultMap.put(field.get(item), item);
                    }
                    return resultMap;
                default:
                    log.warn("未实现的方法: {}", methodName);
                    throw new UnsupportedOperationException("未实现的方法: " + methodName);
            }
        }
        
        /**
         * 处理QueryWrapper
         */
        @SuppressWarnings("unchecked")
        private List<T> handleQueryWrapper(QueryWrapper<?> queryWrapper, SqlSession sqlSession) {
            // 生成查询SQL
            String sql = "SELECT * FROM " + tableName;
            
            // 获取查询条件
            String whereClause = queryWrapper.getCustomSqlSegment();
            if (whereClause != null && !whereClause.isEmpty()) {
                // 处理WHERE关键字
                if (whereClause.startsWith("AND")) {
                    sql += " WHERE " + whereClause.substring(4);
                } else if (whereClause.startsWith("WHERE")) {
                    sql += " " + whereClause;
                } else {
                    sql += " WHERE " + whereClause;
                }
            }
            
            // 使用动态查询
            Map<String, Object> params = new HashMap<>();
            
            return executeDynamicQueryList(sql, params, sqlSession, entityClass);
        }
        
        /**
         * 处理插入操作
         */
        private int handleInsert(Object entity, SqlSession sqlSession) {
            try {
                StringBuilder columns = new StringBuilder();
                StringBuilder values = new StringBuilder();
                Map<String, Object> params = new HashMap<>();
                
                // 获取实体类的所有字段
                for (Field field : entityClass.getDeclaredFields()) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    String columnName = camelToUnderscore(fieldName);
                    Object value = field.get(entity);
                    
                    if (value != null) {
                        if (columns.length() > 0) {
                            columns.append(", ");
                            values.append(", ");
                        }
                        
                        columns.append(columnName);
                        values.append("#{")
                             .append(fieldName)
                             .append("}");
                        params.put(fieldName, value);
                    }
                }
                
                String sql = "INSERT INTO " + tableName + " (" + columns + ") VALUES (" + values + ")";
                return sqlSession.insert("com.hjw.dynamicdatasource.mapper.DynamicMapper.dynamicExecute", 
                        createDynamicExecuteParam(sql, params));
            } catch (Exception e) {
                log.error("处理插入操作失败", e);
                throw new RuntimeException("处理插入操作失败", e);
            }
        }
        
        /**
         * 处理更新操作
         */
        private int handleUpdateById(Object entity, SqlSession sqlSession) {
            try {
                StringBuilder setClause = new StringBuilder();
                Map<String, Object> params = new HashMap<>();
                Object idValue = null;
                
                // 获取实体类的所有字段
                for (Field field : entityClass.getDeclaredFields()) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    Object value = field.get(entity);
                    
                    if ("id".equals(fieldName)) {
                        idValue = value;
                        params.put("id", value);
                    } else if (value != null) {
                        String columnName = camelToUnderscore(fieldName);
                        
                        if (setClause.length() > 0) {
                            setClause.append(", ");
                        }
                        
                        setClause.append(columnName)
                               .append(" = #{")
                               .append(fieldName)
                               .append("}");
                        params.put(fieldName, value);
                    }
                }
                
                if (idValue == null) {
                    throw new IllegalArgumentException("实体类ID不能为空");
                }
                
                String sql = "UPDATE " + tableName + " SET " + setClause + " WHERE id = #{id}";
                return sqlSession.update("com.hjw.dynamicdatasource.mapper.DynamicMapper.dynamicExecute", 
                        createDynamicExecuteParam(sql, params));
            } catch (Exception e) {
                log.error("处理更新操作失败", e);
                throw new RuntimeException("处理更新操作失败", e);
            }
        }
        
        /**
         * 执行动态查询（单行）
         */
        @SuppressWarnings("unchecked")
        private T executeDynamicQuery(String sql, Map<String, Object> params, SqlSession sqlSession, Class<T> resultType) {
            Map<String, Object> dynamicParams = new HashMap<>();
            dynamicParams.put("sql", sql);
            dynamicParams.put("params", params);
            dynamicParams.put("entityClass", resultType);

            List<T> results = sqlSession.selectList("com.hjw.dynamicdatasource.mapper.DynamicMapper.dynamicQuery", dynamicParams);
            return results != null && !results.isEmpty() ? results.get(0) : null;
        }
        
        /**
         * 执行动态查询（列表）
         */
        @SuppressWarnings("unchecked")
        private List<T> executeDynamicQueryList(String sql, Map<String, Object> params, SqlSession sqlSession, Class<T> resultType) {
            Map<String, Object> dynamicParams = new HashMap<>();
            dynamicParams.put("sql", sql);
            dynamicParams.put("params", params);
            dynamicParams.put("entityClass", resultType);

            // 获取配置
            Configuration configuration = sqlSessionFactory.getConfiguration();
            
            try {
                // 注册类型别名，确保MyBatis能够正确识别和映射结果类型
                String typeAlias = resultType.getSimpleName();
                configuration.getTypeAliasRegistry().registerAlias(typeAlias, resultType);

                
                // 执行查询
                return convertMapsToEntities(sqlSession.selectList("com.hjw.dynamicdatasource.mapper.DynamicMapper.dynamicQuery", dynamicParams), resultType);
            } catch (Exception e) {
                log.error("执行动态查询列表失败: {}", sql, e);
                // 如果映射失败，尝试手动映射结果
                List<Map<String, Object>> maps = sqlSession.selectList("com.hjw.dynamicdatasource.mapper.DynamicMapper.dynamicQuery", dynamicParams);
                return convertMapsToEntities(maps, resultType);
            }
        }
        
        /**
         * 将Map列表转换为实体类列表
         */
        @SuppressWarnings("unchecked")
        private List<T> convertMapsToEntities(List<Map<String, Object>> maps, Class<T> entityClass) {
            List<T> entities = new ArrayList<>();
            
            if (maps == null || maps.isEmpty()) {
                return entities;
            }
            
            try {
                for (Map<String, Object> map : maps) {
                    // 创建实体实例
                    T entity = entityClass.newInstance();
                    
                    // 设置属性值
                    for (Field field : entityClass.getDeclaredFields()) {
                        field.setAccessible(true);
                        String fieldName = field.getName();
                        String columnName = camelToUnderscore(fieldName);
                        
                        // 尝试直接使用字段名或下划线形式作为key
                        Object value = null;
                        if (map.containsKey(fieldName)) {
                            value = map.get(fieldName);
                        } else if (map.containsKey(columnName)) {
                            value = map.get(columnName);
                        }
                        
                        if (value != null) {
                            // 类型转换
                            field.set(entity, convertValue(value, field.getType()));
                        }
                    }
                    
                    entities.add(entity);
                }
            } catch (Exception e) {
                log.error("将Map转换为实体类失败,{}", e.toString());
            }
            
            return entities;
        }
        
        /**
         * 转换值类型
         */
        private Object convertValue(Object value, Class<?> targetType) {
            if (value == null || targetType.isAssignableFrom(value.getClass())) {
                return value;
            }
            // 简单类型转换
            if (targetType == String.class) {
                return value.toString();
            } else if (targetType == Integer.class || targetType == int.class) {
                return Integer.parseInt(value.toString());
            } else if (targetType == Long.class || targetType == long.class) {
                return Long.parseLong(value.toString());
            } else if (targetType == Double.class || targetType == double.class) {
                return Double.parseDouble(value.toString());
            } else if (targetType == Boolean.class || targetType == boolean.class) {
                return Boolean.parseBoolean(value.toString());
            } else if (targetType == Date.class) {
                if (value instanceof String) {
                    try {
                        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse((String) value);
                    } catch (ParseException e) {
                        // 尝试其他日期格式
                        return new Date();
                    }
                } else if (value instanceof Number) {
                    return new Date(((Number) value).longValue());
                }
            }
            
            return value;
        }
        
        /**
         * 创建动态执行参数
         */
        private Map<String, Object> createDynamicExecuteParam(String sql, Map<String, Object> params) {
            Map<String, Object> dynamicParams = new HashMap<>();
            dynamicParams.put("sql", sql);
            dynamicParams.put("params", params);
            return dynamicParams;
        }
    }
    
    /**
     * 动态执行SQL查询
     * @param sql SQL语句
     * @param params 参数
     * @param entityClass 实体类
     * @return 查询结果列表
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> executeQuery(String sql, Map<String, Object> params, Class<T> entityClass) {
        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {
            // 创建参数映射，包含SQL和参数
            Map<String, Object> dynamicParams = new HashMap<>();
            dynamicParams.put("sql", sql);
            dynamicParams.put("params", params);
            dynamicParams.put("entityClass", entityClass);
            
            return sqlSession.selectList("com.hjw.dynamicdatasource.mapper.DynamicMapper.dynamicQuery", dynamicParams);
        } catch (Exception e) {
            log.error("执行动态查询失败: {}", sql, e);
            throw new RuntimeException("执行动态查询失败", e);
        }
    }
    
    /**
     * 清除Mapper缓存
     */
    public void clearCache() {
        dynamicCacheManager.clear();
    }
}